const fs = require("fs");
const util = require("util");
const Files = require("../models/Files");

const writeFile = util.promisify(fs.writeFile);
const appendFile = util.promisify(fs.appendFile);
const unlinkFile = util.promisify(fs.unlink);
const statFile = util.promisify(fs.stat);

const CHUNK_SIZE = 1024 * 1024; // 分块大小为 1MB

/**
 * 将文件分块上传到服务器
 * @param {Object} file - 上传的文件数据
 * @param {string} fileId - 文件ID
 * @param {number} chunkNumber - 当前分块号
 * @param {number} totalChunks - 总分块数
 * @returns {Promise<Object>} - 上传成功的文件信息
 */
const uploadFile = async (file, fileId, chunkNumber, totalChunks) => {
  try {

    // 保存分块文件到磁盘的逻辑
    const filePath = `uploads/${fileId}`;
    await appendFile(`${filePath}.part`, file.data);

    // 检查是否所有分块都已上传
    if (chunkNumber === totalChunks) {
      // 合并所有分块为最终文件
      const finalFilePath = `uploads/${file.newFilename}`;
      await mergeChunks(filePath, finalFilePath);

      // 删除分块文件
      await unlinkFile(`${filePath}.part`);

      // 将文件信息存储到数据库的逻辑
      const uploadedFile = new Files({
        filename: file.newFilename,
        path: finalFilePath,
        size: file.size,
      });
      await uploadedFile.save();

      return uploadedFile;
    }
  } catch (error) {
    throw new Error("文件上传失败。");
  }
};

/**
 * 合并分块文件为最终文件
 * @param {string} filePath - 分块文件的路径
 * @param {string} finalFilePath - 最终文件的路径
 */
const mergeChunks = async (filePath, finalFilePath) => {
  try {
    const partFilePaths = await getPartFilePaths(filePath);
    const writeStream = fs.createWriteStream(finalFilePath);

    for (const partFilePath of partFilePaths) {
      const partReadStream = fs.createReadStream(partFilePath);
      await pipeStream(partReadStream, writeStream);
      await unlinkFile(partFilePath);
    }

    writeStream.end();
  } catch (error) {
    throw new Error("文件合并失败。");
  }
};

/**
 * 获取分块文件的路径列表
 * @param {string} filePath - 分块文件的路径
 * @returns {Promise<Array<string>>} - 分块文件的路径列表
 */
const getPartFilePaths = async (filePath) => {
  const dirPath = filePath.substring(0, filePath.lastIndexOf("/"));
  const files = await util.promisify(fs.readdir)(dirPath);

  const partFilePaths = files
    .filter((file) => file.startsWith(filePath) && file.endsWith(".part"))
    .sort((a, b) => {
      const aChunkNumber = parseInt(a.substring(a.lastIndexOf(".") + 1));
      const bChunkNumber = parseInt(b.substring(b.lastIndexOf(".") + 1));
      return aChunkNumber - bChunkNumber;
    })
    .map((file) => `${dirPath}/${file}`);

  return partFilePaths;
};

/**
* 将数据流从读取流管道传输到写入流
* @param {ReadStream} readStream - 读取流
* @param {WriteStream} writeStream - 写入流
* @returns {Promise<void>} */
const pipeStream = (readStream, writeStream) => {
  return new Promise((resolve, reject) => {
    readStream.on("error", (error) => {
      reject(error);
    });
    writeStream.on("error", (error) => {
      reject(error);
    });
    writeStream.on("finish", () => {
      resolve();
    });
    readStream.pipe(writeStream);
  });
};

/**
 * 删除文件
 * @param {string} fileId - 文件ID
 * @returns {Promise<void>} */
const deleteFile = async (fileId) => {
  try {
    // 删除文件的逻辑
    await Files.findByIdAndDelete(fileId);
  } catch (error) {
    throw new Error("删除文件失败。");
  }
};

/**
 * 获取文件信息
 * @param {string} fileId - 文件ID
 * @returns {Promise<Object>} - 文件信息 */
const getFile = async (fileId) => {
  try {
    // 获取文件的逻辑
    const file = await Files.findById(fileId);
    return file;
  } catch (error) {
    throw new Error("获取文件失败。");
  }
};

const uploadFiles = async (files, userId = '') => {
  try {
    const state = files.length ? true : false
    if(state) {
      const list = []
      for (let i = 0; i < files.length; i++) {
        const finalFilePath = `/${files[i].newFilename}`;
        const uploadedFile = new Files({
          filename: files[i].newFilename,
          path: finalFilePath,
          size: files[i].size,
          UserId: userId || null
        });
        const res = await uploadedFile.save();
        list.push(res)
      }
      return list
    }
    // console.log(files);
    const finalFilePath = `/${files.newFilename}`;
    const uploadedFile = new Files({
      filename: files.newFilename,
      path: finalFilePath,
      size: files.size,
    });
    await uploadedFile.save();
    return uploadedFile;

  } catch (error) {
    throw new Error('上传文件失败~')
  }
}



module.exports = { uploadFile, deleteFile, getFile, CHUNK_SIZE, uploadFiles };
